Download course materials (.zip file) from here after 2nd June.

bit.ly/RforLinguists-201906

These packages should already be installed on the lab computers. Please make sure you have installed them on your laptop before tomorrow, if you are using one.

install.packages(tidyverse,ordinal,lme4)

1 Introduction: R and RStudio

This workshop is designed to introduce you to practical uses and issues in R and RStudio, aimed at linguists and psychologists (well, psycholinguists). In this first day, we will start with the fundamentals of interacting with the programs.

R is a programming language that we can use to tell the computer what to do. We can “speak” R to the computer a number of ways, e.g., through the command line (Terminal in Macs) or through the R app.

Before you can use R and RStudio, it’s important to understand what you’re looking at and where to find things.

1.1 R vs RStudio

1.1.1 What is the difference between R and RStudio?

R is the program and programming language that allows you to input commands and get the computer to do things. In order to interact with R, some people use a simple R interface, some people use the command line, and some people use RStudio.

RStudio is a GUI (Graphical User Interface) that allows you to interact with R and keep everything organised.

R interface Command line RStudio

We’ll be using RStudio because it is the easiest to use, with some point-and-click commands, but still with the full functionality and power of R. R runs in the background when you run RStudio, but RStudio takes care of that on its own so all you need to do is open RStudio.

1.1.2 What is going on in the RStudio window?

The RStudio interface has (up to) four panes that you can rearrange and customise to suit your needs. Here is the default configuration:

When you open RStudio for the first time, there may only be three panes.

1.1.2.1 The Console

The console is your direct line of communication with R. It operates a bit like a chat window (if you’re familiar with that) because you can type things into the console, hit ENTER, and R will do something (and sometimes, depending on what you type, it’ll respond). You know the console is listening and ready to accept a new command if you see a > on the left edge of the window on the lowest line of text.

1.1.2.2 Environment

The environment is a set of three tabs that effectively lets us see into “R’s brain” (thanks Danielle!). This window lets you see what variables you’ve created, what datasets are loaded in, what packages and libraries are loaded, among many other things. Right now, it’s empty.

If we click on Global Environment, we can see what packages have automatically be loaded into this R session. Once you load other packages in, you will see them here too.

1.1.2.3 Files etc

The pane in the lower right has five tabs by default.

  1. Files
    • This tab will show you what files are in the folders you navigate to.
    • This is useful if you want to preview a dataset, open a script, or figure out where you saved something.
  2. Plots
    • This tab will display plots you generate from the console.
    • You can click Zoom to pop the graph out into a separate window and resize it.
    • You can click Export to save the plot as a PNG, PDF, EPS, etc.
  3. Packages
    • In this tab, you can see what packages have been downloaded and loaded.
  4. Help
    • This tab will let you look through the documentation and get tips on how to use different functions.
  5. Viewer
    • I’ve never used this.

1.2 Best practices

How do you keep all your related files organised?

Keeping your files organised will make your life infinitely easier and will help you ease back into using R if you come back to it after a hiatus. The RStudio interface will help with this, but there is no better foundation than good file management.

1.2.1 Your project folder

Danielle Turton and I suggest the following as a best practice:

  1. Create a folder with the name of your project.
    • If possible, do not use SPACES or SPECIAL CHARACTERS. These can cause issues across platforms.
    • If you want to separate words, use UNDERSCORES (_), HYPHENS (-), or CamelCase.
  2. Within your project folder, create three subfolders.
    • data: This is the place you’ll store all your datasets and spreadsheets.
    • graphs: This is the place you’ll save the outputs of your script.
    • scripts: This is the place you’ll save your R scripts and notebooks.
  3. Name all scripts, graphs, and datasets using the following templates:
    • YYYYMMDD-descriptive_name.R
    • YYYYMMDD-name_of_generating_script_or_dataset.PNG
    • YYYYMMDD-dataset_name_or_source.csv (or .txt)

1.2.2 Creating an .RProj

RStudio offers a neat feature called a project (file type .Rproj). A project keeps all your scripts and datasets handy and can save variables for use later, even if you quit and restart RStudio. This can be useful if you are running complex models, for instance.

To create a new project, click on the small triangle in the upper right corner of the RStudio window.

This will bring up a menu with a number of useful options, but right now, we want to create a New Project…

Since we have already created a folder (i.e., a directory) for our project, we can click on the Existing Directory option. If you haven’t created a folder for your project, you can create a new directory, but in this case you should still follow best practices for file organisation.

From this window, we can browse our computers for the location of the folder we’ve set up.

1.2.3 Troubleshooting

I have noticed that sometimes students whose computers are set up with a non-English language, particularly with a non-Latin alphabet, can run into problems with setting up these folders. It is important to instruct them to use only Latin characters for the folders that R and RStudio will access, as non-Latin characters use a type of encoding that not all programs can read.

2 Base R functionality

2.1 Scripts

Scripts will appear in the fourth pane (top left by default).

Scripts are simply text files, they are not R and they don’t do anything unless you perform specific actions on them. They’re a bit like instruction manuals, but R can only read them if you manually send the instructions to the console (more on this later).

2.1.1 What is the point of a script?

A script is a way to save your work so you only need to write the code once. Once you’ve written a script once, you can execute it as many times as you like, but you won’t need to write it again. You can copy and paste other people’s code into your script and tweak it to fit your needs. You can debug your code without having to type it in new each time. You can share your code with others, and you can leave comments to yourself in your code so that you can leave it sit for a while and then remember what you were doing when you come back to it.

2.1.2 How do you write a new script?

On all platforms: the green + symbol in the top left corner will let you create a new script.

On a Mac: command+shift+N
On a PC:

The symbol # hides the text that follows on that line from R, that is, it “comments it out”. This lets you write comments to yourself and to anyone else who might read your code. You’ll want to do this so you can remember what you were doing (trust me, you will not remember) and so other people can replicate what you did (even if it’s just to help you debug your code later).

If you type print("Hello World!") (with a nice comment) and then hit ENTER in your console, you will see something like this:

> print("Hello World!") # this line will produce the text between the quotes

[1] "Hello World!"

If you type print("Hello World!") and hit ENTER in a script, you will see something like this:

print("Hello World!")  
 

(Note that nothing happens. There is no output. A script is just a text file.)

2.1.3 How do you use a script?

Open a new script and type print("Hello World!") into it. How do you get R to execute your code? There are a couple ways:

  • Click the Run button on the top right portion of the script pane.
    • This will run everything in your script.
  • Use a keyboard shortcut
    • To run only the line your cursor is on, Command+Enter
    • To run only the selected code, select some code and use Command+Enter
    • To run the entire script, Command+Shift+Enter

When you run a script, the text in the script is sent, line by line, to the console. Once in the console, R executes the code. You can watch the code progress in the console. If there is any text or numerical output, it will appear in the console. If there is a graphical output, it will appear in the Plots tab of the lower right pane (Files etc).

2.1.4 Saving in RStudio

Now that we’ve gone through the fundamentals of organisation and basic R operators, we can get into the more important task of reading data and writing output (i.e., saving our work).

Once you’ve created a project (.Rproj), you can open the project and it should open right to where you left off. This means your scripts will open as well, as long as you did not close them the last time you worked on the project. However, if you want to open a script that isn’t currrently open but does exist, you can do so in the Files tab of the lower right pane. Click on the name of the script, and it will open in a new tab of your scripts pane (top left by default).

2.2 R is a calculator

Its least unique function is to compute arithmetic. You probably don’t want to use R just to add sums, but you could do.

3 + 4

White space doesn’t matter for most things (so you can put spaces between numbers, operations, names).

3+4

Order of operations follows standard rules (BIDMAS / BODMAS / PEMDAS):

3*4^2
(3*4)^2

2.2.1 Try it for yourself

  1. Create a new script.
  2. Save and name the script appropriately. (YYYYMMDD-descriptive_name.R)
  3. In the script, enter the following code:

    print("Hello world!")
    3 + 4
    7^2
  4. Run the entire script.

Your console should end up looking like this:

> print("Hello world!")
[1] "Hello world!"
> 3 + 4
[1] 7
> 7^2
[1] 49
>

(In the rest of this document, instead of output starting with >, it may start with ##. This is due to how R compiles a script to an HTML document and does not change anything in the script, code, or contentful output.)

2.2.1.1 What does [1] mean?

The number in square brackets to the left of the output indicates the number of values that have been printed by index number. That is, if there are multiple outputs on one line, [1] will appear. If the seventh item in the output wraps around and appears on the second line, both [1] and [7] will appear. This is useful when trying to make sense of long lists of numbers, for instance.

Below, I saved two longer strings of text into one variable called longText. Then when it’s printed, it appears on two lines. The [1] indicates the first item in the list is the first item on the line and the [2] indicates the second item in the list is the first item that appears on that line.

longText <- c("i don't think we'll be able to fit this text on one line of the output console","so that it might wrap around and display on two lines")
print(longText)  

2.2.2 What is a variable?

One of the most important components of (almost) any programming language is a variable. A variable is an object that can be assigned a value, a list of values, a matrix of values, or something along those lines. A variable in R can be named almost anything with a few exceptions:

A variable name…

  • Cannot start with a number
  • Cannot contain white space (i.e., spaces, tabs, line breaks)
  • Can contain . or _ but cannot contain other non-alphanumeric characters
  • Should begin with a lowercase letter
  • Should be memorable and descriptive
  • Should not be too long or difficult to type
  • Should not be too vague or general

To assign a value (etc) to a variable, there are three possible operators: =, <-, or occasionally -> (the latter two look like arrows).

First we assign the value of 3 to the variable x. Notice that spaces between the numbers and the operator are optional. I like to use them to help see each component more clearly.

x = 3 # or x=3
x

We can also use one of the arrow operators. The two characters that comprise the arrow cannot have space between them. They act as a single unit. For the leftward-facing arrow, the value(s) on the right are assigned to the variable on the left.

y <- 4 # or y<-4
y

Now that we’ve assigned values to x and y, we can do things to them. Below, I demonstrate some basic arthimetic operators that allow R to act like a calculator.

x + y
x * y
x / y
x ^ y

Finally, the rightward-pointing arrow is used very rarely, but functions in a similar way to the other two assignment operators. The value(s) on the left are assigned to the variable on the right.

x + y -> z # or z <- x + y or z=x+y
z

To assign more than one value to a variable, there are several functions we can use, but the most common and easiest is c(). To read more about the function c(), you can type c into the search bar in the help tab in the lower right pane, or you can input the following into your console:

?c

In short, this function combines a series of values into a vector or list.

c(1,2,3)
c("1","2","3")
c("one","two","three")
c(one,two,three)

Note that bare numbers are green and are output without quotation marks, numbers and words in quotation marks are output as such, but words without quotation marks produce an error. This is because R assumes that all words without quotation marks are variables, but we haven’t created variables named one, two, or three.

one = 1
two = 2
three = 3
c(one,two,three)

2.3 R is for interacting with data files

Dataset sleep:

head(sleep)
  • column 1 = how many extra hours of sleep were recorded
  • column 2 = which drug was administered
  • column 3 = which participant

3 Indicies

3.1 Finding the index of the value you want

What does this do?

sleep[1,]

How does this differ from [1,]?

sleep[2,] # so that means this is row 2

How does this differ from [3,]?

sleep[,3] # what do you think this is?

…which makes it dataset[row,column]

3.3 More descriptive methods

You can also navigate with column names:

sleep$ID

How would you view the column extra?

sleep$extra

Use str() to get a summary of the structure of the dataset

str(sleep)

What are all the unique values in ID?

unique(sleep$extra)

What’s the value in the first row, third column?

sleep[1,3]

What’s the first element in the column ID?

sleep[1,]$ID
sleep$ID[1]

You can also view the dataset as a spreadsheet (although it can’t be altered).

View(sleep)
LS0tCnRpdGxlOiAiKipXb3Jrc2hvcCoqIgphdXRob3I6ICJEciBMYXVyZW4gTSBBY2tlcm1hbiIKZGF0ZTogIjAzIEpVTiAyMDE5IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19mbG9hdDogCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgdGhlbWU6IHNhbmRzdG9uZQogICAgaGlnaGxpZ2h0OiBkZWZhdWx0Ci0tLQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQoKCiMgMS4gUiBhbmQgUlN0dWRpbyBpbnRlcmZhY2VzLCBSTWFya2Rvd24sIGFuZCBiZXN0IHByYWN0aWNlcwojICAgIC0gQmFzaWMgZnVuY3Rpb25hbGl0eSwgc2hvcnRjdXRzLCB3cml0aW5nIHNjcmlwdHMgYW5kIG5vdGVib29rcywgb3JnYW5pc2luZyBmaWxlcywgaW50ZXJmYWNpbmcgd2l0aCBHaXRIdWIKIyAyLiBEYXRhIGZyYW1lIG1hbmlwdWxhdGlvbiB1c2luZyBUaWR5dmVyc2UKIyAgICAtIFBpcGluZyBzeW50YXggYW5kIGNvZGUgcmVwbGljYWJpbGl0eQojICAgIC0gVGlkeXIsIERwbHlyLCByZWxhdGVkIHBhY2thZ2VzCiMgICAgLSBDbGVhbmluZywgY29tYmluaW5nLCBhbmQgcmVhcnJhbmdpbmcgZGF0YSBmcmFtZXMKIyAzLiBEYXRhIHZpc3VhbGlzYXRpb24gdXNpbmcgZ2dwbG90IGFuZCBiZXN0IHByYWN0aWNlcwojICAgIC0gU3RydWN0dXJlIGFuZCBzeW50YXggb2YgZ2dwbG90IGFuZCBnZW9tCiMgICAgLSBDdXN0b21pc2luZyBhbmQgY29tYmluaW5nIHBsb3RzCiMgICAgLSBEZXRlcm1pbmluZyB3aGF0IHBsb3QgaXMgYmVzdCBmb3IgeW91ciBkYXRhCiMgNC4gQmFzaWMgbGluZWFyIG1vZGVscyB3aXRob3V0IGFuZCB3aXRoIG1peGVkIGVmZmVjdHMgKGluY2x1ZGluZyBnYXVzc2lhbiwgYmlub21pYWwsIGFuZCBvcmRpbmFsKQojICAgIC0gYnVpbGRpbmcvc2VsZWN0aW5nIGFuIGFwcHJvcHJpYXRlIG1vZGVsLCBpbmNsdWRpbmcgcmFuZG9tIGVmZmVjdCBzdHJ1Y3R1cmVzCiMgICAgLSBtYXhpbWFsIHZzIHBhcnNpbW9uaW91cyBtb2RlbHMKIyAgICAtIHByYWN0aWNhbCB1c2Ugb2YgbG0oKSwgbG1lcigpLCBnbG0oKSwgZ2xtZXIoKSwgY2xtbSgpCiMgICAgLSBkdW1teSBjb2RpbmcgdnMgY29udHJhc3QgY29kaW5nCiMgICAgLSBpbnRlcnByZXRpbmcgdGhlIG91dHB1dApgYGAKCkRvd25sb2FkIGNvdXJzZSBtYXRlcmlhbHMgKC56aXAgZmlsZSkgZnJvbSBbaGVyZV0oaHR0cDovL2JpdC5seS9SZm9yTGluZ3Vpc3RzLTIwMTkwNikgKmFmdGVyIDJuZCBKdW5lKi4KClsqKmJpdC5seS9SZm9yTGluZ3Vpc3RzLTIwMTkwNioqXShodHRwOi8vYml0Lmx5L1Jmb3JMaW5ndWlzdHMtMjAxOTA2KQoKVGhlc2UgcGFja2FnZXMgc2hvdWxkIGFscmVhZHkgYmUgaW5zdGFsbGVkIG9uIHRoZSBsYWIgY29tcHV0ZXJzLiBQbGVhc2UgbWFrZSBzdXJlIHlvdSBoYXZlIGluc3RhbGxlZCB0aGVtIG9uIHlvdXIgbGFwdG9wIGJlZm9yZSAqKnRvbW9ycm93KiosIGlmIHlvdSBhcmUgdXNpbmcgb25lLgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXModGlkeXZlcnNlLG9yZGluYWwsbG1lNCkKYGBgCgojIEludHJvZHVjdGlvbjogUiBhbmQgUlN0dWRpbyAKClRoaXMgd29ya3Nob3AgaXMgZGVzaWduZWQgdG8gaW50cm9kdWNlIHlvdSB0byBwcmFjdGljYWwgdXNlcyBhbmQgaXNzdWVzIGluIFIgYW5kIFJTdHVkaW8sIGFpbWVkIGF0IGxpbmd1aXN0cyBhbmQgcHN5Y2hvbG9naXN0cyAod2VsbCwgcHN5Y2hvbGluZ3Vpc3RzKS4gSW4gdGhpcyBmaXJzdCBkYXksIHdlIHdpbGwgc3RhcnQgd2l0aCB0aGUgZnVuZGFtZW50YWxzIG9mIGludGVyYWN0aW5nIHdpdGggdGhlIHByb2dyYW1zLgoKUiBpcyBhIHByb2dyYW1taW5nIGxhbmd1YWdlIHRoYXQgd2UgY2FuIHVzZSB0byB0ZWxsIHRoZSBjb21wdXRlciB3aGF0IHRvIGRvLiBXZSBjYW4gInNwZWFrIiBSIHRvIHRoZSBjb21wdXRlciBhIG51bWJlciBvZiB3YXlzLCBlLmcuLCB0aHJvdWdoIHRoZSBjb21tYW5kIGxpbmUgKFRlcm1pbmFsIGluIE1hY3MpIG9yIHRocm91Z2ggdGhlIFIgYXBwLgoKQmVmb3JlIHlvdSBjYW4gdXNlIFIgYW5kIFJTdHVkaW8sIGl0J3MgaW1wb3J0YW50IHRvIHVuZGVyc3RhbmQgd2hhdCB5b3UncmUgbG9va2luZyBhdCBhbmQgd2hlcmUgdG8gZmluZCB0aGluZ3MuCgojIyBSIHZzIFJTdHVkaW8gCgojIyMgV2hhdCBpcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIFIgYW5kIFJTdHVkaW8/CgoqKlIqKiBpcyB0aGUgcHJvZ3JhbSBhbmQgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgdGhhdCBhbGxvd3MgeW91IHRvIGlucHV0IGNvbW1hbmRzIGFuZCBnZXQgdGhlIGNvbXB1dGVyIHRvIGRvIHRoaW5ncy4gSW4gb3JkZXIgdG8gaW50ZXJhY3Qgd2l0aCBSLCBzb21lIHBlb3BsZSB1c2UgYSBzaW1wbGUgUiBpbnRlcmZhY2UsIHNvbWUgcGVvcGxlIHVzZSB0aGUgY29tbWFuZCBsaW5lLCBhbmQgc29tZSBwZW9wbGUgdXNlIFJTdHVkaW8uCgoqKlJTdHVkaW8qKiBpcyBhIEdVSSAoR3JhcGhpY2FsIFVzZXIgSW50ZXJmYWNlKSB0aGF0IGFsbG93cyB5b3UgdG8gaW50ZXJhY3Qgd2l0aCBSIGFuZCBrZWVwIGV2ZXJ5dGhpbmcgb3JnYW5pc2VkLgoKIVsqUiBpbnRlcmZhY2UqXSguLi9ndWkvci1pbnRlcmZhY2UucG5nKQohWypDb21tYW5kIGxpbmUqXSguLi9ndWkvdGVybWluYWwucG5nKQohWypSU3R1ZGlvKl0oLi4vZ3VpL3JpZ2h0LXBhbmVscy5wbmcpCgpXZSdsbCBiZSB1c2luZyAqKlJTdHVkaW8qKiBiZWNhdXNlIGl0IGlzIHRoZSBlYXNpZXN0IHRvIHVzZSwgd2l0aCBzb21lIHBvaW50LWFuZC1jbGljayBjb21tYW5kcywgYnV0IHN0aWxsIHdpdGggdGhlIGZ1bGwgZnVuY3Rpb25hbGl0eSBhbmQgcG93ZXIgb2YgUi4gUiBydW5zIGluIHRoZSBiYWNrZ3JvdW5kIHdoZW4geW91IHJ1biBSU3R1ZGlvLCBidXQgUlN0dWRpbyB0YWtlcyBjYXJlIG9mIHRoYXQgb24gaXRzIG93biBzbyBhbGwgeW91IG5lZWQgdG8gZG8gaXMgb3BlbiBSU3R1ZGlvLgoKIyMjIFdoYXQgaXMgZ29pbmcgb24gaW4gdGhlIFJTdHVkaW8gd2luZG93PwoKVGhlIFJTdHVkaW8gaW50ZXJmYWNlIGhhcyAodXAgdG8pIGZvdXIgcGFuZXMgdGhhdCB5b3UgY2FuIHJlYXJyYW5nZSBhbmQgY3VzdG9taXNlIHRvIHN1aXQgeW91ciBuZWVkcy4gSGVyZSBpcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uOgoKIVtdKC4uL2d1aS9jb25zb2xlLnBuZykKV2hlbiB5b3Ugb3BlbiBSU3R1ZGlvIGZvciB0aGUgZmlyc3QgdGltZSwgdGhlcmUgbWF5IG9ubHkgYmUgdGhyZWUgcGFuZXMuCgojIyMjIFRoZSBDb25zb2xlCgpUaGUgY29uc29sZSBpcyB5b3VyIGRpcmVjdCBsaW5lIG9mIGNvbW11bmljYXRpb24gd2l0aCBSLiBJdCBvcGVyYXRlcyBhIGJpdCBsaWtlIGEgY2hhdCB3aW5kb3cgKGlmIHlvdSdyZSBmYW1pbGlhciB3aXRoIHRoYXQpIGJlY2F1c2UgeW91IGNhbiB0eXBlIHRoaW5ncyBpbnRvIHRoZSBjb25zb2xlLCBoaXQgYEVOVEVSYCwgYW5kIFIgd2lsbCBkbyBzb21ldGhpbmcgKGFuZCBzb21ldGltZXMsIGRlcGVuZGluZyBvbiB3aGF0IHlvdSB0eXBlLCBpdCdsbCByZXNwb25kKS4gWW91IGtub3cgdGhlIGNvbnNvbGUgaXMgbGlzdGVuaW5nIGFuZCByZWFkeSB0byBhY2NlcHQgYSBuZXcgY29tbWFuZCBpZiB5b3Ugc2VlIGEgYD5gIG9uIHRoZSBsZWZ0IGVkZ2Ugb2YgdGhlIHdpbmRvdyBvbiB0aGUgbG93ZXN0IGxpbmUgb2YgdGV4dC4KCiMjIyMgRW52aXJvbm1lbnQKClRoZSBlbnZpcm9ubWVudCBpcyBhIHNldCBvZiB0aHJlZSB0YWJzIHRoYXQgZWZmZWN0aXZlbHkgbGV0cyB1cyBzZWUgaW50byAiUidzIGJyYWluIiAodGhhbmtzIERhbmllbGxlISkuIFRoaXMgd2luZG93IGxldHMgeW91IHNlZSB3aGF0IHZhcmlhYmxlcyB5b3UndmUgY3JlYXRlZCwgd2hhdCBkYXRhc2V0cyBhcmUgbG9hZGVkIGluLCB3aGF0IHBhY2thZ2VzIGFuZCBsaWJyYXJpZXMgYXJlIGxvYWRlZCwgYW1vbmcgbWFueSBvdGhlciB0aGluZ3MuIFJpZ2h0IG5vdywgaXQncyBlbXB0eS4KCklmIHdlIGNsaWNrIG9uIGBHbG9iYWwgRW52aXJvbm1lbnRgLCB3ZSBjYW4gc2VlIHdoYXQgcGFja2FnZXMgaGF2ZSBhdXRvbWF0aWNhbGx5IGJlIGxvYWRlZCBpbnRvIHRoaXMgUiBzZXNzaW9uLiBPbmNlIHlvdSBsb2FkIG90aGVyIHBhY2thZ2VzIGluLCB5b3Ugd2lsbCBzZWUgdGhlbSBoZXJlIHRvby4KCmBgYHtyLCBlY2hvPUZBTFNFfQpodG1sdG9vbHM6OmltZyhzcmMgPSBrbml0cjo6aW1hZ2VfdXJpKCIuLi9ndWkvZ2xvYmFsX2Vudmlyb25tZW50LnBuZyIpLCAKICAgICAgICAgICAgICAgYWx0ID0gJ2xvZ28nLCAKICAgICAgICAgICAgICAgc3R5bGUgPSAncG9zaXRpb246cmVsYXRpdmU7IHRvcDowOyByaWdodDowOyBwYWRkaW5nOjEwcHg7IHdpZHRoOjcwJScpCmBgYAoKIyMjIyBGaWxlcyBldGMKClRoZSBwYW5lIGluIHRoZSBsb3dlciByaWdodCBoYXMgZml2ZSB0YWJzIGJ5IGRlZmF1bHQuCgoxLiAqKkZpbGVzKiogIAogICAgLSBUaGlzIHRhYiB3aWxsIHNob3cgeW91IHdoYXQgZmlsZXMgYXJlIGluIHRoZSBmb2xkZXJzIHlvdSBuYXZpZ2F0ZSB0by4gIAogICAgLSBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBwcmV2aWV3IGEgZGF0YXNldCwgb3BlbiBhIHNjcmlwdCwgb3IgZmlndXJlIG91dCB3aGVyZSB5b3Ugc2F2ZWQgc29tZXRoaW5nLiAgCjIuICoqUGxvdHMqKiAgCiAgICAtIFRoaXMgdGFiIHdpbGwgZGlzcGxheSBwbG90cyB5b3UgZ2VuZXJhdGUgZnJvbSB0aGUgY29uc29sZS4gIAogICAgLSBZb3UgY2FuIGNsaWNrIGBab29tYCB0byBwb3AgdGhlIGdyYXBoIG91dCBpbnRvIGEgc2VwYXJhdGUgd2luZG93IGFuZCByZXNpemUgaXQuICAKICAgIC0gWW91IGNhbiBjbGljayBgRXhwb3J0YCB0byBzYXZlIHRoZSBwbG90IGFzIGEgUE5HLCBQREYsIEVQUywgZXRjLiAgCjMuICoqUGFja2FnZXMqKiAgCiAgICAtIEluIHRoaXMgdGFiLCB5b3UgY2FuIHNlZSB3aGF0IHBhY2thZ2VzIGhhdmUgYmVlbiBkb3dubG9hZGVkIGFuZCBsb2FkZWQuCjQuICoqSGVscCoqICAKICAgIC0gVGhpcyB0YWIgd2lsbCBsZXQgeW91IGxvb2sgdGhyb3VnaCB0aGUgZG9jdW1lbnRhdGlvbiBhbmQgZ2V0IHRpcHMgb24gaG93IHRvIHVzZSBkaWZmZXJlbnQgZnVuY3Rpb25zLgo1LiAqKlZpZXdlcioqICAKICAgIC0gSSd2ZSBuZXZlciB1c2VkIHRoaXMuICAKCiMjIEJlc3QgcHJhY3RpY2VzIAoKSG93IGRvIHlvdSBrZWVwIGFsbCB5b3VyIHJlbGF0ZWQgZmlsZXMgb3JnYW5pc2VkPwoKS2VlcGluZyB5b3VyIGZpbGVzIG9yZ2FuaXNlZCB3aWxsIG1ha2UgeW91ciBsaWZlIGluZmluaXRlbHkgZWFzaWVyIGFuZCB3aWxsIGhlbHAgeW91IGVhc2UgYmFjayBpbnRvIHVzaW5nIFIgaWYgeW91IGNvbWUgYmFjayB0byBpdCBhZnRlciBhIGhpYXR1cy4gVGhlIFJTdHVkaW8gaW50ZXJmYWNlIHdpbGwgaGVscCB3aXRoIHRoaXMsIGJ1dCB0aGVyZSBpcyBubyBiZXR0ZXIgZm91bmRhdGlvbiB0aGFuIGdvb2QgZmlsZSBtYW5hZ2VtZW50LgoKIyMjIFlvdXIgcHJvamVjdCBmb2xkZXIKCltEYW5pZWxsZSBUdXJ0b25dKGh0dHBzOi8vd3d3LnN0YWZmLm5jbC5hYy51ay9kYW5pZWxsZS50dXJ0b24vKSBhbmQgSSBzdWdnZXN0IHRoZSBmb2xsb3dpbmcgYXMgYSBiZXN0IHByYWN0aWNlOgoKMS4gQ3JlYXRlIGEgZm9sZGVyIHdpdGggdGhlIG5hbWUgb2YgeW91ciBwcm9qZWN0LiAgCiAgICAtIElmIHBvc3NpYmxlLCBkbyBub3QgdXNlIFNQQUNFUyBvciBTUEVDSUFMIENIQVJBQ1RFUlMuIFRoZXNlIGNhbiBjYXVzZSBpc3N1ZXMgYWNyb3NzIHBsYXRmb3Jtcy4gIAogICAgLSBJZiB5b3Ugd2FudCB0byBzZXBhcmF0ZSB3b3JkcywgdXNlIFVOREVSU0NPUkVTIChfKSwgSFlQSEVOUyAoLSksIG9yIENhbWVsQ2FzZS4gIAoyLiBXaXRoaW4geW91ciBwcm9qZWN0IGZvbGRlciwgY3JlYXRlIHRocmVlIHN1YmZvbGRlcnMuICAKICAgIC0gKipkYXRhKio6IFRoaXMgaXMgdGhlIHBsYWNlIHlvdSdsbCBzdG9yZSBhbGwgeW91ciBkYXRhc2V0cyBhbmQgc3ByZWFkc2hlZXRzLiAgCiAgICAtICoqZ3JhcGhzKio6IFRoaXMgaXMgdGhlIHBsYWNlIHlvdSdsbCBzYXZlIHRoZSBvdXRwdXRzIG9mIHlvdXIgc2NyaXB0LiAgCiAgICAtICoqc2NyaXB0cyoqOiBUaGlzIGlzIHRoZSBwbGFjZSB5b3UnbGwgc2F2ZSB5b3VyIFIgc2NyaXB0cyBhbmQgbm90ZWJvb2tzLiAgCjMuIE5hbWUgYWxsIHNjcmlwdHMsIGdyYXBocywgYW5kIGRhdGFzZXRzIHVzaW5nIHRoZSBmb2xsb3dpbmcgdGVtcGxhdGVzOiAgCiAgICAtIFlZWVlNTURELWRlc2NyaXB0aXZlX25hbWUuUiAgCiAgICAtIFlZWVlNTURELW5hbWVfb2ZfZ2VuZXJhdGluZ19zY3JpcHRfb3JfZGF0YXNldC5QTkcgIAogICAgLSBZWVlZTU1ERC1kYXRhc2V0X25hbWVfb3Jfc291cmNlLmNzdiAob3IgLnR4dCkgIAoKIVtdKC4uL2d1aS9mb2xkZXIucG5nKQoKIyMjIENyZWF0aW5nIGFuIC5SUHJvagoKUlN0dWRpbyBvZmZlcnMgYSBuZWF0IGZlYXR1cmUgY2FsbGVkIGEgKnByb2plY3QqIChmaWxlIHR5cGUgYC5ScHJvamApLiBBIHByb2plY3Qga2VlcHMgYWxsIHlvdXIgc2NyaXB0cyBhbmQgZGF0YXNldHMgaGFuZHkgYW5kIGNhbiBzYXZlIHZhcmlhYmxlcyBmb3IgdXNlIGxhdGVyLCBldmVuIGlmIHlvdSBxdWl0IGFuZCByZXN0YXJ0IFJTdHVkaW8uIFRoaXMgY2FuIGJlIHVzZWZ1bCBpZiB5b3UgYXJlIHJ1bm5pbmcgY29tcGxleCBtb2RlbHMsIGZvciBpbnN0YW5jZS4KClRvIGNyZWF0ZSBhIG5ldyBwcm9qZWN0LCBjbGljayBvbiB0aGUgc21hbGwgdHJpYW5nbGUgaW4gdGhlIHVwcGVyIHJpZ2h0IGNvcm5lciBvZiB0aGUgUlN0dWRpbyB3aW5kb3cuCgohW10oLi4vZ3VpL25ldy1wcm9qZWN0LnBuZykKClRoaXMgd2lsbCBicmluZyB1cCBhIG1lbnUgd2l0aCBhIG51bWJlciBvZiB1c2VmdWwgb3B0aW9ucywgYnV0IHJpZ2h0IG5vdywgd2Ugd2FudCB0byBjcmVhdGUgYSAqTmV3IFByb2plY3QuLi4qCgohW10oLi4vZ3VpL2V4aXN0aW5nLWRpcmVjdG9yeS5wbmcpCgpTaW5jZSB3ZSBoYXZlIGFscmVhZHkgY3JlYXRlZCBhIGZvbGRlciAoaS5lLiwgYSBkaXJlY3RvcnkpIGZvciBvdXIgcHJvamVjdCwgd2UgY2FuIGNsaWNrIG9uIHRoZSAqRXhpc3RpbmcgRGlyZWN0b3J5KiBvcHRpb24uIElmIHlvdSBoYXZlbid0IGNyZWF0ZWQgYSBmb2xkZXIgZm9yIHlvdXIgcHJvamVjdCwgeW91IGNhbiBjcmVhdGUgYSBuZXcgZGlyZWN0b3J5LCBidXQgaW4gdGhpcyBjYXNlIHlvdSBzaG91bGQgc3RpbGwgZm9sbG93IGJlc3QgcHJhY3RpY2VzIGZvciBmaWxlIG9yZ2FuaXNhdGlvbi4KCiFbXSguLi9ndWkvYnJvd3NlLnBuZykKCkZyb20gdGhpcyB3aW5kb3csIHdlIGNhbiBicm93c2Ugb3VyIGNvbXB1dGVycyBmb3IgdGhlIGxvY2F0aW9uIG9mIHRoZSBmb2xkZXIgd2UndmUgc2V0IHVwLgoKIyMjIFRyb3VibGVzaG9vdGluZwoKSSBoYXZlIG5vdGljZWQgdGhhdCBzb21ldGltZXMgc3R1ZGVudHMgd2hvc2UgY29tcHV0ZXJzIGFyZSBzZXQgdXAgd2l0aCBhIG5vbi1FbmdsaXNoIGxhbmd1YWdlLCBwYXJ0aWN1bGFybHkgd2l0aCBhIG5vbi1MYXRpbiBhbHBoYWJldCwgY2FuIHJ1biBpbnRvIHByb2JsZW1zIHdpdGggc2V0dGluZyB1cCB0aGVzZSBmb2xkZXJzLiBJdCBpcyBpbXBvcnRhbnQgdG8gaW5zdHJ1Y3QgdGhlbSB0byB1c2Ugb25seSBMYXRpbiBjaGFyYWN0ZXJzIGZvciB0aGUgZm9sZGVycyB0aGF0IFIgYW5kIFJTdHVkaW8gd2lsbCBhY2Nlc3MsIGFzIG5vbi1MYXRpbiBjaGFyYWN0ZXJzIHVzZSBhIHR5cGUgb2YgZW5jb2RpbmcgdGhhdCBub3QgYWxsIHByb2dyYW1zIGNhbiByZWFkLgoKIyBCYXNlIFIgZnVuY3Rpb25hbGl0eSAKCiMjIFNjcmlwdHMKClNjcmlwdHMgd2lsbCBhcHBlYXIgaW4gdGhlIGZvdXJ0aCBwYW5lICh0b3AgbGVmdCBieSBkZWZhdWx0KS4gCgohW10oLi4vZ3VpL25ldy1zY3JpcHQucG5nKQoKU2NyaXB0cyBhcmUgc2ltcGx5IHRleHQgZmlsZXMsIHRoZXkgYXJlIG5vdCBSIGFuZCB0aGV5IGRvbid0IGRvIGFueXRoaW5nIHVubGVzcyB5b3UgcGVyZm9ybSBzcGVjaWZpYyBhY3Rpb25zIG9uIHRoZW0uIFRoZXkncmUgYSBiaXQgbGlrZSBpbnN0cnVjdGlvbiBtYW51YWxzLCBidXQgUiBjYW4gb25seSByZWFkIHRoZW0gaWYgeW91IG1hbnVhbGx5IHNlbmQgdGhlIGluc3RydWN0aW9ucyB0byB0aGUgY29uc29sZSAobW9yZSBvbiB0aGlzIGxhdGVyKS4KCiMjIyBXaGF0IGlzIHRoZSBwb2ludCBvZiBhIHNjcmlwdD8KCioqQSBzY3JpcHQgaXMgYSB3YXkgdG8gc2F2ZSB5b3VyIHdvcmsgc28geW91IG9ubHkgbmVlZCB0byB3cml0ZSB0aGUgY29kZSBvbmNlLioqIE9uY2UgeW91J3ZlIHdyaXR0ZW4gYSBzY3JpcHQgb25jZSwgeW91IGNhbiBleGVjdXRlIGl0IGFzIG1hbnkgdGltZXMgYXMgeW91IGxpa2UsIGJ1dCB5b3Ugd29uJ3QgbmVlZCB0byAqd3JpdGUqIGl0IGFnYWluLiBZb3UgY2FuIGNvcHkgYW5kIHBhc3RlIG90aGVyIHBlb3BsZSdzIGNvZGUgaW50byB5b3VyIHNjcmlwdCBhbmQgdHdlYWsgaXQgdG8gZml0IHlvdXIgbmVlZHMuIFlvdSBjYW4gZGVidWcgeW91ciBjb2RlIHdpdGhvdXQgaGF2aW5nIHRvIHR5cGUgaXQgaW4gbmV3IGVhY2ggdGltZS4gWW91IGNhbiBzaGFyZSB5b3VyIGNvZGUgd2l0aCBvdGhlcnMsIGFuZCB5b3UgY2FuIGxlYXZlIGNvbW1lbnRzIHRvIHlvdXJzZWxmIGluIHlvdXIgY29kZSBzbyB0aGF0IHlvdSBjYW4gbGVhdmUgaXQgc2l0IGZvciBhIHdoaWxlIGFuZCB0aGVuIHJlbWVtYmVyIHdoYXQgeW91IHdlcmUgZG9pbmcgd2hlbiB5b3UgY29tZSBiYWNrIHRvIGl0LgoKIyMjIEhvdyBkbyB5b3Ugd3JpdGUgYSBuZXcgc2NyaXB0PwoKT24gYWxsIHBsYXRmb3JtczogdGhlIGdyZWVuICsgc3ltYm9sIGluIHRoZSB0b3AgbGVmdCBjb3JuZXIgd2lsbCBsZXQgeW91IGNyZWF0ZSBhIG5ldyBzY3JpcHQuCgpPbiBhIE1hYzogYGNvbW1hbmRgK2BzaGlmdGArYE5gICAKT24gYSBQQzogIAoKVGhlIHN5bWJvbCBgI2AgaGlkZXMgdGhlIHRleHQgdGhhdCBmb2xsb3dzIG9uIHRoYXQgbGluZSBmcm9tIFIsIHRoYXQgaXMsIGl0ICJjb21tZW50cyBpdCBvdXQiLiBUaGlzIGxldHMgeW91IHdyaXRlIGNvbW1lbnRzIHRvIHlvdXJzZWxmIGFuZCB0byBhbnlvbmUgZWxzZSB3aG8gbWlnaHQgcmVhZCB5b3VyIGNvZGUuIFlvdSdsbCB3YW50IHRvIGRvIHRoaXMgc28geW91IGNhbiByZW1lbWJlciB3aGF0IHlvdSB3ZXJlIGRvaW5nICgqdHJ1c3QqIG1lLCB5b3Ugd2lsbCBub3QgcmVtZW1iZXIpIGFuZCBzbyBvdGhlciBwZW9wbGUgY2FuIHJlcGxpY2F0ZSB3aGF0IHlvdSBkaWQgKGV2ZW4gaWYgaXQncyBqdXN0IHRvIGhlbHAgeW91IGRlYnVnIHlvdXIgY29kZSBsYXRlcikuCgpJZiB5b3UgdHlwZSBgcHJpbnQoIkhlbGxvIFdvcmxkISIpYCAod2l0aCBhIG5pY2UgY29tbWVudCkgYW5kIHRoZW4gaGl0IGBFTlRFUmAgaW4geW91ciBjb25zb2xlLCB5b3Ugd2lsbCBzZWUgc29tZXRoaW5nIGxpa2UgdGhpczoKCmBgYAo+IHByaW50KCJIZWxsbyBXb3JsZCEiKSAjIHRoaXMgbGluZSB3aWxsIHByb2R1Y2UgdGhlIHRleHQgYmV0d2VlbiB0aGUgcXVvdGVzCmBgYApgWzFdICJIZWxsbyBXb3JsZCEiYAoKSWYgeW91IHR5cGUgYHByaW50KCJIZWxsbyBXb3JsZCEiKWAgYW5kIGhpdCBgRU5URVJgIGluIGEgc2NyaXB0LCB5b3Ugd2lsbCBzZWUgc29tZXRoaW5nIGxpa2UgdGhpczoKCmBgYApwcmludCgiSGVsbG8gV29ybGQhIikgIAogCmBgYAoKKE5vdGUgdGhhdCBub3RoaW5nIGhhcHBlbnMuIFRoZXJlIGlzIG5vIG91dHB1dC4gQSBzY3JpcHQgaXMganVzdCBhIHRleHQgZmlsZS4pCgojIyMgSG93IGRvIHlvdSB1c2UgYSBzY3JpcHQ/IAoKT3BlbiBhIG5ldyBzY3JpcHQgYW5kIHR5cGUgYHByaW50KCJIZWxsbyBXb3JsZCEiKWAgaW50byBpdC4gSG93IGRvIHlvdSBnZXQgUiB0byBleGVjdXRlIHlvdXIgY29kZT8gVGhlcmUgYXJlIGEgY291cGxlIHdheXM6ICAKCi0gQ2xpY2sgdGhlIGBSdW5gIGJ1dHRvbiBvbiB0aGUgdG9wIHJpZ2h0IHBvcnRpb24gb2YgdGhlIHNjcmlwdCBwYW5lLgogICAgLSBUaGlzIHdpbGwgcnVuIGV2ZXJ5dGhpbmcgaW4geW91ciBzY3JpcHQuCi0gVXNlIGEga2V5Ym9hcmQgc2hvcnRjdXQKICAgIC0gVG8gcnVuIG9ubHkgdGhlIGxpbmUgeW91ciBjdXJzb3IgaXMgb24sIGBDb21tYW5kYCtgRW50ZXJgCiAgICAtIFRvIHJ1biBvbmx5IHRoZSBzZWxlY3RlZCBjb2RlLCBzZWxlY3Qgc29tZSBjb2RlIGFuZCB1c2UgYENvbW1hbmRgK2BFbnRlcmAKICAgIC0gVG8gcnVuIHRoZSBlbnRpcmUgc2NyaXB0LCBgQ29tbWFuZGArYFNoaWZ0YCtgRW50ZXJgCgpXaGVuIHlvdSBydW4gYSBzY3JpcHQsIHRoZSB0ZXh0IGluIHRoZSBzY3JpcHQgaXMgc2VudCwgbGluZSBieSBsaW5lLCB0byB0aGUgY29uc29sZS4gT25jZSBpbiB0aGUgY29uc29sZSwgUiBleGVjdXRlcyB0aGUgY29kZS4gWW91IGNhbiB3YXRjaCB0aGUgY29kZSBwcm9ncmVzcyBpbiB0aGUgY29uc29sZS4gSWYgdGhlcmUgaXMgYW55IHRleHQgb3IgbnVtZXJpY2FsIG91dHB1dCwgaXQgd2lsbCBhcHBlYXIgaW4gdGhlIGNvbnNvbGUuIElmIHRoZXJlIGlzIGEgZ3JhcGhpY2FsIG91dHB1dCwgaXQgd2lsbCBhcHBlYXIgaW4gdGhlIFBsb3RzIHRhYiBvZiB0aGUgbG93ZXIgcmlnaHQgcGFuZSAoRmlsZXMgZXRjKS4KCiMjIyBTYXZpbmcgaW4gUlN0dWRpbwoKTm93IHRoYXQgd2UndmUgZ29uZSB0aHJvdWdoIHRoZSBmdW5kYW1lbnRhbHMgb2Ygb3JnYW5pc2F0aW9uIGFuZCBiYXNpYyBSIG9wZXJhdG9ycywgd2UgY2FuIGdldCBpbnRvIHRoZSBtb3JlIGltcG9ydGFudCB0YXNrIG9mIHJlYWRpbmcgZGF0YSBhbmQgd3JpdGluZyBvdXRwdXQgKGkuZS4sIHNhdmluZyBvdXIgd29yaykuCgpPbmNlIHlvdSd2ZSBjcmVhdGVkIGEgcHJvamVjdCAoLlJwcm9qKSwgeW91IGNhbiBvcGVuIHRoZSBwcm9qZWN0IGFuZCBpdCBzaG91bGQgb3BlbiByaWdodCB0byB3aGVyZSB5b3UgbGVmdCBvZmYuIFRoaXMgbWVhbnMgeW91ciBzY3JpcHRzIHdpbGwgb3BlbiBhcyB3ZWxsLCBhcyBsb25nIGFzIHlvdSBkaWQgbm90IGNsb3NlIHRoZW0gdGhlIGxhc3QgdGltZSB5b3Ugd29ya2VkIG9uIHRoZSBwcm9qZWN0LiBIb3dldmVyLCBpZiB5b3Ugd2FudCB0byBvcGVuIGEgc2NyaXB0IHRoYXQgaXNuJ3QgY3VycnJlbnRseSBvcGVuIGJ1dCBkb2VzIGV4aXN0LCB5b3UgY2FuIGRvIHNvIGluIHRoZSBGaWxlcyB0YWIgb2YgdGhlIGxvd2VyIHJpZ2h0IHBhbmUuIENsaWNrIG9uIHRoZSBuYW1lIG9mIHRoZSBzY3JpcHQsIGFuZCBpdCB3aWxsIG9wZW4gaW4gYSBuZXcgdGFiIG9mIHlvdXIgc2NyaXB0cyBwYW5lICh0b3AgbGVmdCBieSBkZWZhdWx0KS4KCiFbXSguLi9ndWkvbmV3LXNjcmlwdC5wbmcpCgojIyBSIGlzIGEgY2FsY3VsYXRvcgoKSXRzIGxlYXN0IHVuaXF1ZSBmdW5jdGlvbiBpcyB0byBjb21wdXRlIGFyaXRobWV0aWMuIFlvdSBwcm9iYWJseSBkb24ndCB3YW50IHRvIHVzZSBSIGp1c3QgdG8gYWRkIHN1bXMsIGJ1dCB5b3UgY291bGQgZG8uCmBgYHtyfQozICsgNApgYGAKCldoaXRlIHNwYWNlIGRvZXNuJ3QgbWF0dGVyIGZvciBtb3N0IHRoaW5ncyAoc28geW91IGNhbiBwdXQgc3BhY2VzIGJldHdlZW4gbnVtYmVycywgb3BlcmF0aW9ucywgbmFtZXMpLgpgYGB7cn0KMys0CmBgYAoKT3JkZXIgb2Ygb3BlcmF0aW9ucyBmb2xsb3dzIHN0YW5kYXJkIHJ1bGVzIChCSURNQVMgLyBCT0RNQVMgLyBQRU1EQVMpOgpgYGB7cn0KMyo0XjIKYGBgCmBgYHtyfQooMyo0KV4yCmBgYAoKCiMjIyAqKlRyeSBpdCBmb3IgeW91cnNlbGYqKgoKMS4gQ3JlYXRlIGEgbmV3IHNjcmlwdC4KMi4gU2F2ZSBhbmQgbmFtZSB0aGUgc2NyaXB0IGFwcHJvcHJpYXRlbHkuIChZWVlZTU1ERC1kZXNjcmlwdGl2ZV9uYW1lLlIpCjMuIEluIHRoZSBzY3JpcHQsIGVudGVyIHRoZSBmb2xsb3dpbmcgY29kZTogIApgYGAKcHJpbnQoIkhlbGxvIHdvcmxkISIpCjMgKyA0CjdeMgpgYGAKNC4gUnVuIHRoZSBlbnRpcmUgc2NyaXB0LgoKWW91ciBjb25zb2xlIHNob3VsZCBlbmQgdXAgbG9va2luZyBsaWtlIHRoaXM6ICAKYGBgCj4gcHJpbnQoIkhlbGxvIHdvcmxkISIpClsxXSAiSGVsbG8gd29ybGQhIgo+IDMgKyA0ClsxXSA3Cj4gN14yClsxXSA0OQo+CmBgYAoKKEluIHRoZSByZXN0IG9mIHRoaXMgZG9jdW1lbnQsIGluc3RlYWQgb2Ygb3V0cHV0IHN0YXJ0aW5nIHdpdGggYD5gLCBpdCBtYXkgc3RhcnQgd2l0aCBgIyNgLiBUaGlzIGlzIGR1ZSB0byBob3cgUiBjb21waWxlcyBhIHNjcmlwdCB0byBhbiBIVE1MIGRvY3VtZW50IGFuZCBkb2VzIG5vdCBjaGFuZ2UgYW55dGhpbmcgaW4gdGhlIHNjcmlwdCwgY29kZSwgb3IgY29udGVudGZ1bCBvdXRwdXQuKQoKIyMjIyBXaGF0IGRvZXMgYFsxXWAgbWVhbj8KClRoZSBudW1iZXIgaW4gc3F1YXJlIGJyYWNrZXRzIHRvIHRoZSBsZWZ0IG9mIHRoZSBvdXRwdXQgaW5kaWNhdGVzIHRoZSBudW1iZXIgb2YgdmFsdWVzIHRoYXQgaGF2ZSBiZWVuIHByaW50ZWQgYnkgaW5kZXggbnVtYmVyLiBUaGF0IGlzLCBpZiB0aGVyZSBhcmUgbXVsdGlwbGUgb3V0cHV0cyBvbiBvbmUgbGluZSwgWzFdIHdpbGwgYXBwZWFyLiBJZiB0aGUgc2V2ZW50aCBpdGVtIGluIHRoZSBvdXRwdXQgd3JhcHMgYXJvdW5kIGFuZCBhcHBlYXJzIG9uIHRoZSBzZWNvbmQgbGluZSwgYm90aCBbMV0gYW5kIFs3XSB3aWxsIGFwcGVhci4gVGhpcyBpcyB1c2VmdWwgd2hlbiB0cnlpbmcgdG8gbWFrZSBzZW5zZSBvZiBsb25nIGxpc3RzIG9mIG51bWJlcnMsIGZvciBpbnN0YW5jZS4KCkJlbG93LCBJIHNhdmVkIHR3byBsb25nZXIgc3RyaW5ncyBvZiB0ZXh0IGludG8gb25lIHZhcmlhYmxlIGNhbGxlZCBgbG9uZ1RleHRgLiBUaGVuIHdoZW4gaXQncyBwcmludGVkLCBpdCBhcHBlYXJzIG9uIHR3byBsaW5lcy4gVGhlIGBbMV1gIGluZGljYXRlcyB0aGUgZmlyc3QgaXRlbSBpbiB0aGUgbGlzdCBpcyB0aGUgZmlyc3QgaXRlbSBvbiB0aGUgbGluZSBhbmQgdGhlIGBbMl1gIGluZGljYXRlcyB0aGUgc2Vjb25kIGl0ZW0gaW4gdGhlIGxpc3QgaXMgdGhlIGZpcnN0IGl0ZW0gdGhhdCBhcHBlYXJzIG9uIHRoYXQgbGluZS4KCmBgYHtyIGxvbmd0ZXh0fQpsb25nVGV4dCA8LSBjKCJpIGRvbid0IHRoaW5rIHdlJ2xsIGJlIGFibGUgdG8gZml0IHRoaXMgdGV4dCBvbiBvbmUgbGluZSBvZiB0aGUgb3V0cHV0IGNvbnNvbGUiLCJzbyB0aGF0IGl0IG1pZ2h0IHdyYXAgYXJvdW5kIGFuZCBkaXNwbGF5IG9uIHR3byBsaW5lcyIpCnByaW50KGxvbmdUZXh0KSAgCmBgYAoKIyMjIFdoYXQgaXMgYSB2YXJpYWJsZT8KCk9uZSBvZiB0aGUgbW9zdCBpbXBvcnRhbnQgY29tcG9uZW50cyBvZiAoYWxtb3N0KSBhbnkgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgaXMgYSAqdmFyaWFibGUqLiBBIHZhcmlhYmxlIGlzIGFuIG9iamVjdCB0aGF0IGNhbiBiZSBhc3NpZ25lZCBhIHZhbHVlLCBhIGxpc3Qgb2YgdmFsdWVzLCBhIG1hdHJpeCBvZiB2YWx1ZXMsIG9yIHNvbWV0aGluZyBhbG9uZyB0aG9zZSBsaW5lcy4gQSB2YXJpYWJsZSBpbiBSIGNhbiBiZSBuYW1lZCBhbG1vc3QgYW55dGhpbmcgd2l0aCBhIGZldyBleGNlcHRpb25zOgoKQSB2YXJpYWJsZSBuYW1l4oCmICAKCi0gQ2Fubm90IHN0YXJ0IHdpdGggYSBudW1iZXIgIAotIENhbm5vdCBjb250YWluIHdoaXRlIHNwYWNlIChpLmUuLCBzcGFjZXMsIHRhYnMsIGxpbmUgYnJlYWtzKSAgCi0gQ2FuIGNvbnRhaW4gYC5gIG9yIGBfYCBidXQgY2Fubm90IGNvbnRhaW4gb3RoZXIgbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzICAKLSBTaG91bGQgYmVnaW4gd2l0aCBhIGxvd2VyY2FzZSBsZXR0ZXIgIAotIFNob3VsZCBiZSBtZW1vcmFibGUgYW5kIGRlc2NyaXB0aXZlICAKLSBTaG91bGQgbm90IGJlIHRvbyBsb25nIG9yIGRpZmZpY3VsdCB0byB0eXBlICAKLSBTaG91bGQgbm90IGJlIHRvbyB2YWd1ZSBvciBnZW5lcmFsICAKClRvIGFzc2lnbiBhIHZhbHVlIChldGMpIHRvIGEgdmFyaWFibGUsIHRoZXJlIGFyZSB0aHJlZSBwb3NzaWJsZSBvcGVyYXRvcnM6IGA9YCwgYDwtYCwgb3Igb2NjYXNpb25hbGx5IGAtPmAgKHRoZSBsYXR0ZXIgdHdvIGxvb2sgbGlrZSBhcnJvd3MpLgoKRmlyc3Qgd2UgYXNzaWduIHRoZSB2YWx1ZSBvZiAzIHRvIHRoZSB2YXJpYWJsZSBgeGAuIE5vdGljZSB0aGF0IHNwYWNlcyBiZXR3ZWVuIHRoZSBudW1iZXJzIGFuZCB0aGUgb3BlcmF0b3IgYXJlIG9wdGlvbmFsLiBJIGxpa2UgdG8gdXNlIHRoZW0gdG8gaGVscCBzZWUgZWFjaCBjb21wb25lbnQgbW9yZSBjbGVhcmx5LgoKYGBge3J9CnggPSAzICMgb3IgeD0zCngKYGBgCgpXZSBjYW4gYWxzbyB1c2Ugb25lIG9mIHRoZSBhcnJvdyBvcGVyYXRvcnMuIFRoZSB0d28gY2hhcmFjdGVycyB0aGF0IGNvbXByaXNlIHRoZSBhcnJvdyBjYW5ub3QgaGF2ZSBzcGFjZSBiZXR3ZWVuIHRoZW0uIFRoZXkgYWN0IGFzIGEgc2luZ2xlIHVuaXQuIEZvciB0aGUgbGVmdHdhcmQtZmFjaW5nIGFycm93LCB0aGUgdmFsdWUocykgb24gdGhlIHJpZ2h0IGFyZSBhc3NpZ25lZCB0byB0aGUgdmFyaWFibGUgb24gdGhlIGxlZnQuCgpgYGB7cn0KeSA8LSA0ICMgb3IgeTwtNAp5CmBgYAoKTm93IHRoYXQgd2UndmUgYXNzaWduZWQgdmFsdWVzIHRvIGB4YCBhbmQgYHlgLCB3ZSBjYW4gZG8gdGhpbmdzIHRvIHRoZW0uIEJlbG93LCBJIGRlbW9uc3RyYXRlIHNvbWUgYmFzaWMgYXJ0aGltZXRpYyBvcGVyYXRvcnMgdGhhdCBhbGxvdyBSIHRvIGFjdCBsaWtlIGEgY2FsY3VsYXRvci4KCmBgYHtyfQp4ICsgeQp4ICogeQp4IC8geQp4IF4geQpgYGAKCkZpbmFsbHksIHRoZSByaWdodHdhcmQtcG9pbnRpbmcgYXJyb3cgaXMgdXNlZCB2ZXJ5IHJhcmVseSwgYnV0IGZ1bmN0aW9ucyBpbiBhIHNpbWlsYXIgd2F5IHRvIHRoZSBvdGhlciB0d28gYXNzaWdubWVudCBvcGVyYXRvcnMuIFRoZSB2YWx1ZShzKSBvbiB0aGUgbGVmdCBhcmUgYXNzaWduZWQgdG8gdGhlIHZhcmlhYmxlIG9uIHRoZSByaWdodC4KCmBgYHtyfQp4ICsgeSAtPiB6ICMgb3IgeiA8LSB4ICsgeSBvciB6PXgreQp6CmBgYAoKVG8gYXNzaWduIG1vcmUgdGhhbiBvbmUgdmFsdWUgdG8gYSB2YXJpYWJsZSwgdGhlcmUgYXJlIHNldmVyYWwgZnVuY3Rpb25zIHdlIGNhbiB1c2UsIGJ1dCB0aGUgbW9zdCBjb21tb24gYW5kIGVhc2llc3QgaXMgYGMoKWAuIFRvIHJlYWQgbW9yZSBhYm91dCB0aGUgZnVuY3Rpb24gYGMoKWAsIHlvdSBjYW4gdHlwZSBgY2AgaW50byB0aGUgc2VhcmNoIGJhciBpbiB0aGUgaGVscCB0YWIgaW4gdGhlIGxvd2VyIHJpZ2h0IHBhbmUsICpvciogeW91IGNhbiBpbnB1dCB0aGUgZm9sbG93aW5nIGludG8geW91ciBjb25zb2xlOgpgYGB7cn0KP2MKYGBgCgpJbiBzaG9ydCwgdGhpcyBmdW5jdGlvbiAqY29tYmluZXMqIGEgc2VyaWVzIG9mIHZhbHVlcyBpbnRvIGEgdmVjdG9yIG9yIGxpc3QuCgpgYGB7ciwgbWVzc2FnZT1UUlVFLCBlcnJvcj1UUlVFfQpjKDEsMiwzKQpjKCIxIiwiMiIsIjMiKQpjKCJvbmUiLCJ0d28iLCJ0aHJlZSIpCmMob25lLHR3byx0aHJlZSkKYGBgCgpOb3RlIHRoYXQgYmFyZSBudW1iZXJzIGFyZSBncmVlbiBhbmQgYXJlIG91dHB1dCB3aXRob3V0IHF1b3RhdGlvbiBtYXJrcywgbnVtYmVycyBhbmQgd29yZHMgaW4gcXVvdGF0aW9uIG1hcmtzIGFyZSBvdXRwdXQgYXMgc3VjaCwgYnV0ICp3b3JkcyB3aXRob3V0IHF1b3RhdGlvbiBtYXJrcyBwcm9kdWNlIGFuIGVycm9yKi4gVGhpcyBpcyBiZWNhdXNlIFIgYXNzdW1lcyB0aGF0IGFsbCB3b3JkcyB3aXRob3V0IHF1b3RhdGlvbiBtYXJrcyBhcmUgdmFyaWFibGVzLCBidXQgd2UgaGF2ZW4ndCBjcmVhdGVkIHZhcmlhYmxlcyBuYW1lZCBgb25lYCwgYHR3b2AsIG9yIGB0aHJlZWAuCgpgYGB7cn0Kb25lID0gMQp0d28gPSAyCnRocmVlID0gMwpjKG9uZSx0d28sdGhyZWUpCmBgYAoKCiMjIFIgaXMgZm9yIGludGVyYWN0aW5nIHdpdGggZGF0YSBmaWxlcwoKPiBEYXRhc2V0IGBzbGVlcGA6CgpgYGB7cn0KaGVhZChzbGVlcCkKYGBgCgoqIGNvbHVtbiAxID0gaG93IG1hbnkgZXh0cmEgaG91cnMgb2Ygc2xlZXAgd2VyZSByZWNvcmRlZAoqIGNvbHVtbiAyID0gd2hpY2ggZHJ1ZyB3YXMgYWRtaW5pc3RlcmVkCiogY29sdW1uIDMgPSB3aGljaCBwYXJ0aWNpcGFudAoKIyBJbmRpY2llcyAKIyMgRmluZGluZyB0aGUgaW5kZXggb2YgdGhlIHZhbHVlIHlvdSB3YW50CgpXaGF0IGRvZXMgdGhpcyBkbz8KYGBge3J9CnNsZWVwWzEsXQpgYGAKCkhvdyBkb2VzIHRoaXMgZGlmZmVyIGZyb20gYFsxLF1gPwpgYGB7cn0Kc2xlZXBbMixdICMgc28gdGhhdCBtZWFucyB0aGlzIGlzIHJvdyAyCmBgYAoKSG93IGRvZXMgdGhpcyBkaWZmZXIgZnJvbSBgWzMsXWA/CmBgYHtyfQpzbGVlcFssM10gIyB3aGF0IGRvIHlvdSB0aGluayB0aGlzIGlzPwpgYGAKCuKApndoaWNoIG1ha2VzIGl0IGBkYXRhc2V0W3Jvdyxjb2x1bW5dYAoKIyMgTmF2aWdhdGluZyBiaWdnZXJhdGFzZXRzCgpJbiB5b3VyIHNjcmlwdCAob3IsIGlmIHlvdSBkb24ndCB0YWtlIG15IGFkdmljZSwgaW4geW91ciBjb25zb2xlKSwgeW91IGNhbiBvcGVuIGFuZCBtYW5pcHVsYXRlIGEgZGF0YXNldC4KClJpZ2h0IGNsaWNrIGFuZCBzYXZlIFt0aGlzIGZpbGVdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9WZXJiaW5nTm91bnMvbm90ZWJvb2tzL21hc3Rlci9kYXRhL2Jpbm9taWFsLWRhdGEuY3N2KSB0byB5b3VyIGZvbGRlciBuYW1lZCBgZGF0YWAuCgpgYGB7ciwgZWNobz1GQUxTRX0KZGF0YSA8LSByZWFkLmNzdigiLi4vZGF0YS9iaW5vbWlhbC1kYXRhLmNzdiIpCmBgYAoKYGBge3IsIGVycm9yPVRSVUUsIGV2YWw9RkFMU0V9CmRhdGEgPC0gcmVhZC5jc3YoImRhdGEvYmlub21pYWwtZGF0YS5jc3YiKQpgYGAKCk5vdywgaWYgeW91IHdhbnQgdG8gdmlldyB0aGUgZmlyc3Qgc2l4IHJvd3Mgb2YgdGhlIGRhdGFzZXQgdG8gc2VlIHdoYXQgdHlwZXMgb2YgdGhpbmdzIGFyZSBpbiBpdCwgeW91IGNhbiB1c2UgdGhlIGZ1bmN0aW9uIGBoZWFkKClgLgoKYGBge3IsIGFzaXM9VFJVRX0KaGVhZChkYXRhKQpgYGAKCllvdSBjYW4gYWxzbyBsb29rIGF0IHRoZSBib3R0b20gc2l4IHJvd3Mgd2l0aCBgdGFpbCgpYAoKYGBge3J9CnRhaWwoZGF0YSkKYGBgCgojIyMgQmFzaWMgcXVlcnlpbmcgZnVuY3Rpb25zCgpJZiB3ZSB3YW50IHRvIGZpbmQgb3V0IHdoYXQgZWFjaCBvZiB0aGUgZXhwZXJpbWVudHMgYXJlIGNhbGxlZCwgb3IgaG93IG1hbnkgY29uZGl0aW9ucyB0aGVyZSBhcmUsIHdlIGNhbiB1c2UgdGhlIGZ1bmN0aW9uIGB1bmlxdWUoKWAuIAoKTm90ZSB0aGF0IHdlIG11c3Qgc3BlY2lmeSB3aGF0IHZhcmlhYmxlIG5hbWUgd2UndmUgZ2l2ZW4gb3VyIGRhdGFzZXQgKGBkYXRhYCkgYW5kIHdoYXQgY29sdW1uIHdlIHdhbnQgdG8gcXVlcnkgKGBleHBlcmltZW50YCkuIFRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgZGF0YXNldCBhbmQgdGhlIGNvbHVtbiBpbiB0aGUgZGF0YXNldCBpcyBzcGVjaWZpZWQgd2l0aCB0aGUgYCRgIG9wZXJhdG9yLgoKYGBge3J9CnVuaXF1ZShkYXRhJGV4cGVyaW1lbnQpCmBgYAoKVGhlcmUgYXJlIHRocmVlIGV4cGVyaW1lbnRzLCBhbmQgdGhlaXIgbmFtZXMgYXJlIGAiZmlyc3QiYCwgYCJzZWNvbmQiYCwgYW5kIGAidGhpcmQiYC4gCgpJZiB3ZSB3YW50IHRvIGtub3cgKmhvdyBtYW55KiB1bmlxdWUgdmFsdWVzIHRoZXJlIGFyZSBpbiBhIGNvbHVtbiwgd2UgY2FuIGVtYmVkIHRoZSBgdW5pcXVlKClgIGZ1bmN0aW9uIGluIHRoZSBgbGVuZ3RoKClgIGZ1bmN0aW9uLgoKYGBge3J9Cmxlbmd0aCh1bmlxdWUoZGF0YSRleHBlcmltZW50KSkKYGBgCgpUaGVyZSBhcmUgdGhyZWUgZGlmZmVyZW50IGV4cGVyaW1lbnRzIGluIHRoaXMgZGF0YXNldC4KCiMjIyBDZWxscyB3aXRoaW4gYSBkYXRhc2V0CgpGaW5hbGx5LCBpZiB3ZSB3YW50IHRvIGZpbmQgb3V0IGhvdyBtYW55IHVuaXF1ZSBpdGVtcyB0aGVyZSBhcmUgaW4gZXhwZXJpbWVudCAiZmlyc3QiIG9ubHksIHdlIGNhbiBzcGVjaWZ5IGEgc3Vic2V0IG9mIHRoZSBkYXRhc2V0IHVzaW5nIHNxdWFyZSBicmFja2V0cyBgW11gLiBCZWZvcmUgd2UgZG8gdGhhdCwgdGhvdWdoLCBsZXQncyBnbyB0aHJvdWdoIHdoYXQgdGhlIGFyZ3VtZW50cyBmb3IgdGhlIHNxdWFyZSBicmFja2V0cyBhcmUuCgpBbiAqKmluZGV4KiogcmVmZXJzIHRvIHRoZSBsb2NhdGlvbiBvZiBhbiBpdGVtIGluIGEgbGlzdCwgdmVjdG9yLCBvciBtYXRyaXguCgpJZiB5b3UgaGF2ZSBhIGxpc3QgdGhhdCBsb29rcyBsaWtlIHRoZSBvbmUgYmVsb3csICpncmVlbiogaXMgYXQgaW5kZXggYDRgIChpbiB0aGUgUiBwcm9ncmFtbWluZyBsYW5ndWFnZSkuCgpgWyJyZWQiLCAib3JhbmdlIiwgInllbGxvdyIsICJncmVlbiIsICJibHVlIiwgImluZGlnbyIsICJ2aW9sZXQiXWAKCklmIHlvdSBoYXZlIGEgbWF0cml4IGxpa2UgdGhlIG9uZSBiZWxvdywgeW91IG11c3Qgc3BlY2lmeSB0aGUgaW5kZXggb2YgdGhlIHJvdyBhbmQvb3IgY29sdW1uIChgW3Jvdyxjb2x1bW5dYCkuCgp8IGNvbG91ciB8IHdvcmRMZW5ndGggfCB3YXZlTGVuZ3RoTk0gfAp8LS0tLS0tLS18LS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLXwKfCByZWQgICAgfCAzICAgICAgICAgIHwgNzAwICAgICAgICB8Cnwgb3JhbmdlIHwgNiAgICAgICAgICB8IDYzMCAgICAgICAgfAp8IHllbGxvdyB8IDYgICAgICAgICAgfCA2MDAgICAgICAgIHwKfCBncmVlbiAgfCA1ICAgICAgICAgIHwgNTUwICAgICAgICB8CnwgYmx1ZSAgIHwgNCAgICAgICAgICB8IDQ3MCAgICAgICAgfAp8IGluZGlnbyB8IDYgICAgICAgICAgfCA0MjUgICAgICAgIHwKfCB2aW9sZXQgfCA2ICAgICAgICAgIHwgNDAwICAgICAgICB8CgpUaGUgbG9jYXRpb24gb2YgKmdyZWVuKiBpcyBpbiB0aGUgZm91cnRoIHJvdyBhbmQgdGhlIGZpcnN0IGNvbHVtbiwgc28gd2UgY2FuIGlkZW50aWZ5IGl0IGFzIGBbNCwxXWAuIElmIHdlIG9ubHkgc3BlY2lmeSB0aGUgcm93IChgWzQsXWApLCB3ZSB3aWxsIGdldCBldmVyeXRoaW5nIGluIHRoZSBmb3VydGggcm93IChgImdyZWVuIiwgNCwgNDcwYCkuIElmIHdlIG9ubHkgc3BlY2lmeSB0aGUgZmlyc3QgY29sdW1uLCB3ZSB3aWxsIGdldCBhIGxpc3Qgb2YgY29sb3VycywgbGlrZSB3ZSBkaWQgYWJvdmU6IAoKKGAicmVkIiwgIm9yYW5nZSIsICJ5ZWxsb3ciLCAiZ3JlZW4iLCAiYmx1ZSIsICJpbmRpZ28iLCAidmlvbGV0ImApCgpOb3csIGdvaW5nIGJhY2sgdG8gb3VyIGRhdGFzZXQsIGlmIHdlIHdhbnQgdG8gdmlldyB0aGUgY29udGVudCBvZiBvbmUgY29sdW1uLCBzdWNoIGFzIGBleHBlcmltZW50YCwgd2UgY2FuIHNwZWNpZnkgdGhhdCBjb2x1bW4gd2l0aCB0aGUgYCRgIG9wZXJhdG9yLiBCdXQgaWYgeW91IHdhbnQgdG8gdmlldyBhIHN1YnNldCBvZiBhIGNvbHVtbiwgd2UgY2FuIGFsc28gc3BlY2lmeSB3aGF0IGNyaXRlcmlhIHdlIHdhbnQgdG8gdmlldyAob3IgZG9uJ3Qgd2FudCB0byB2aWV3KS4KCkZvciBpbnN0YW5jZSwgaWYgd2Ugd2FudCB0byB2aWV3IG9ubHkgdGhlIHNlY29uZCBleHBlcmltZW50ICh3aGljaCBpcyBjYWxsZWQgYHNlY29uZGAgaW4gdGhlIGBleHBlcmltZW50YCBjb2x1bW4sIGhlbHBmdWxseSBlbm91Z2gpLCB3ZSBjYW4gdXNlIHRoZSBjb2RlIGJlbG93OgoKYGBge3J9CmRhdGFbZGF0YSRleHBlcmltZW50PT0ic2Vjb25kIixdCmBgYAoKCiMjIE1vcmUgZGVzY3JpcHRpdmUgbWV0aG9kcwoKWW91IGNhbiBhbHNvIG5hdmlnYXRlIHdpdGggY29sdW1uIG5hbWVzOgpgYGB7cn0Kc2xlZXAkSUQKYGBgCgpIb3cgd291bGQgeW91IHZpZXcgdGhlIGNvbHVtbiBgZXh0cmFgPwpgYGB7cn0Kc2xlZXAkZXh0cmEKYGBgCgpVc2UgYHN0cigpYCB0byBnZXQgYSBzdW1tYXJ5IG9mIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGFzZXQKYGBge3J9CnN0cihzbGVlcCkKYGBgCgpXaGF0IGFyZSBhbGwgdGhlIHVuaXF1ZSB2YWx1ZXMgaW4gYElEYD8KYGBge3J9CnVuaXF1ZShzbGVlcCRleHRyYSkKYGBgCgpXaGF0J3MgdGhlIHZhbHVlIGluIHRoZSBmaXJzdCByb3csIHRoaXJkIGNvbHVtbj8KYGBge3J9CnNsZWVwWzEsM10KYGBgCgpXaGF0J3MgdGhlIGZpcnN0IGVsZW1lbnQgaW4gdGhlIGNvbHVtbiBgSURgPwpgYGB7cn0Kc2xlZXBbMSxdJElECnNsZWVwJElEWzFdCmBgYAoKWW91IGNhbiBhbHNvIHZpZXcgdGhlIGRhdGFzZXQgYXMgYSBzcHJlYWRzaGVldCAoYWx0aG91Z2ggaXQgY2FuJ3QgYmUgYWx0ZXJlZCkuCmBgYHtyfQpWaWV3KHNsZWVwKQpgYGAKCg==